using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class TextUnderline : BaseMeshEffect
{
    [Lablel("下划线大小")] public float size = 0.1f;
    [Lablel("下划线偏移")] public float lineOffset = 0;
    [Lablel("下划线颜色")] public Color color = Color.black;

    public override void ModifyMesh(VertexHelper vh)
    {
        if (!IsActive())
            return;
        var text = GetComponent<Text>();
        if (string.IsNullOrEmpty(text.text)) return;

        List<UIVertex> oldList = new List<UIVertex>();
        vh.GetUIVertexStream(oldList);
        int count = oldList.GetCount();
        if (count == 0) return;

        Vector2 extents = text.rectTransform.rect.size;
        var setting = text.GetGenerationSettings(extents);
        TextGenerator underlineText = new TextGenerator();
        underlineText.Populate("-", setting);
        Vector2[] lineUVs = new Vector2[4];
        lineUVs[0] = new Vector2(underlineText.verts[0].uv0.x, underlineText.verts[0].uv0.y);
        lineUVs[1] = new Vector2(underlineText.verts[1].uv0.x, underlineText.verts[1].uv0.y);
        lineUVs[2] = new Vector2(underlineText.verts[2].uv0.x, underlineText.verts[2].uv0.y);
        lineUVs[3] = new Vector2(underlineText.verts[3].uv0.x, underlineText.verts[3].uv0.y);
        var arr = CalculationUVPos(lineUVs);

        var textCache = text.cachedTextGenerator;
        IList<UICharInfo> chars = textCache.characters;
        string str = text.text;
        int lastPoint = (count / 6) * 4 - 3;

        for (int i = 0; i < textCache.lines.Count; i++)
        {
            var line = textCache.lines[i];
            var beginIndex = line.startCharIdx;
            int endIndex = 0;
            if (i == textCache.lines.Count - 1)
            {
                endIndex = chars.Count - 1;
            }
            else
            {
                endIndex = textCache.lines[i + 1].startCharIdx - 1;
            }

            if (beginIndex == endIndex) continue;
            for (int j = beginIndex; j <= endIndex; j++)
            {
                if (!char.IsWhiteSpace(str[j]))
                {
                    beginIndex = j;
                    break;
                }
            }

            for (int j = endIndex; j >= beginIndex; j--)
            {
                if (j >= str.Length) break;
                if (!char.IsWhiteSpace(str[j]))
                {
                    endIndex = j;
                    break;
                }
            }

            if (beginIndex >= endIndex) continue;
            float averageW = 0;
            for (int j = beginIndex; j <= endIndex; j++)
                averageW += chars[j].charWidth;
            averageW = averageW / (endIndex - beginIndex + 1);
            var offW = averageW * size;
            var offH = line.height * size;
            lastPoint = DrawLine(vh, chars[beginIndex].cursorPos.x, chars[endIndex].cursorPos.x + chars[endIndex].charWidth, line.topY - line.height, arr, lastPoint, offW, offH);
        }
    }

    int DrawLine(VertexHelper vh, float posX1, float posX2, float bottomY, Vector2[][] arr, int lastPoint, float offW, float offH)
    {
        var pos1 = new Vector3(posX1 + offW, lineOffset + bottomY, 0);
        var pos2 = new Vector3(posX2 - offW, lineOffset + bottomY, 0);

        var pos3 = pos2 - new Vector3(0, offH, 0);
        var pos4 = pos1 - new Vector3(0, offH, 0);

        vh.AddVert(pos1, color, arr[1][0]);
        vh.AddVert(pos2, color, arr[1][1]);
        vh.AddVert(pos3, color, arr[1][2]);

        vh.AddVert(pos1, color, arr[1][0]);
        vh.AddVert(pos4, color, arr[1][3]);
        vh.AddVert(pos3, color, arr[1][2]);

        lastPoint += 3;
        vh.AddTriangle(lastPoint, lastPoint + 1, lastPoint + 2);
        lastPoint += 3;
        vh.AddTriangle(lastPoint + 2, lastPoint + 1, lastPoint);

        Vector3 v3Offset1 = new Vector3(pos2.x - pos1.x + offW, 0, 0);
        Vector3 v3Offset2 = new Vector3(pos4.y - pos1.y + offW, 0, 0);

        vh.AddVert(pos1 - v3Offset2, color, arr[2][0]);
        vh.AddVert(pos2 - v3Offset1, color, arr[2][1]);
        vh.AddVert(pos3 - v3Offset1, color, arr[2][2]);
        vh.AddVert(pos1 - v3Offset2, color, arr[2][0]);
        vh.AddVert(pos4 - v3Offset2, color, arr[2][3]);
        vh.AddVert(pos3 - v3Offset1, color, arr[2][2]);

        lastPoint += 3;
        vh.AddTriangle(lastPoint + 2, lastPoint + 1, lastPoint);
        lastPoint += 3;
        vh.AddTriangle(lastPoint, lastPoint + 1, lastPoint + 2);

        v3Offset2 = new Vector3(pos2.x - pos1.x + offW, 0, 0);
        v3Offset1 = new Vector3(pos4.y - pos1.y + offW, 0, 0);

        vh.AddVert(pos1 + v3Offset2, color, arr[0][0]);
        vh.AddVert(pos2 + v3Offset1, color, arr[0][1]);
        vh.AddVert(pos3 + v3Offset1, color, arr[0][2]);

        vh.AddVert(pos1 + v3Offset2, color, arr[0][0]);
        vh.AddVert(pos4 + v3Offset2, color, arr[0][3]);
        vh.AddVert(pos3 + v3Offset1, color, arr[0][2]);

        lastPoint += 3;
        vh.AddTriangle(lastPoint + 2, lastPoint + 1, lastPoint);
        lastPoint += 3;
        vh.AddTriangle(lastPoint, lastPoint + 1, lastPoint + 2);
        return lastPoint;
    }

    Vector2[][] CalculationUVPos(in Vector2[] lineUVs)
    {
        Vector2[][] uvs = new Vector2[3][];
        uvs[0] = new Vector2[4];
        uvs[0][0] = lineUVs[0];
        uvs[0][1] = lineUVs[0] * 0.75f + lineUVs[1] * 0.25f;
        uvs[0][2] = lineUVs[2] * 0.25f + lineUVs[3] * 0.75f;
        uvs[0][3] = lineUVs[3];

        uvs[1] = new Vector2[4];
        uvs[1][0] = uvs[0][1];
        uvs[1][1] = lineUVs[0] * 0.25f + lineUVs[1] * 0.75f;
        uvs[1][2] = lineUVs[2] * 0.75f + lineUVs[3] * 0.25f;
        uvs[1][3] = uvs[0][2];

        uvs[2] = new Vector2[4];
        uvs[2][0] = uvs[1][1];
        uvs[2][1] = lineUVs[1];
        uvs[2][2] = lineUVs[2];
        uvs[2][3] = uvs[1][2];

        return uvs;
    }
}